#!/bin/bash
#
# ABOUT:
#
# A notebook app for me to write stuff and keep it, or post it, or whatever.
#
# No "cloud" integration or synching: like a physical notebook, the stuff is
# stored locally, but you can copy the notebook to another computer with Linux.
#
# Backups are your own responsibility: notebook will not do it for you.
#
# Like a notebook, the only security that I can offer is by isolation: your
# notebook is only as secret as you can keep it hidden. I do so because getting
# involved in cryptography to protect involves a much deeper knowledge and
# investment.
#
# DEVELOPMENT ROADMAP:
# 
# It would be good to implement some sort of rudimentary versioning system, 
# although git could be used just as easily. Perhaps a single "rollback?"
#
# Some sort of encryption would be good, although now I can't think much more
# than just pgp encrypting the entire database and unlocking it on the fly.
#
# DEPENDENCIES:
# 
# Notebook depends on sqlite3 to work.
# vim is the standard editor chosen, but you can change the $EDITOR variable.
# When encryption is enabled, you must have gpg correctly configured.
#
# LICENSING:
#
# This program is Free Software released under the terms of the GNU GPLv3
#

#-- configuration variables --
EDITOR="vim"
RECIPIENT="vesonoki@riseup.net"

#-- dependency detection --
if [[ -z $(which sqlite3) ]]
then
    echo "Error: sqlite3 not found."
    echo "This program requires sqlite3 to work."
    echo "Please install it and try again."
    exit 1
fi

if [[ -z $(which gpg) ]]
then
    echo "Error: gpg not found"
    echo "This program requires gpg to work."
    echo "Please install it and try again."
    exit 1
fi

if [[ -z "$RECIPIENT" ]]
then
    echo "Error: no gpg recipient stated."
    echo "Please choose a recipient to encrypt the database to."
    echo "Note that this recipient must also be in your gpg keyring"
    exit 1
fi

if [[ ! -f book.db.gpg ]]
then
    echo "Creating database for first time use..."
    sqlite3 book.db "CREATE TABLE articles (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        title TEXT,
        content TEXT
    )"
    echo "Encrypting database..."
    encrypt
fi

# Like the good textbook-based programmer, I sanitize my database inputs!
sanitize() {
    # $1 is the token
    echo "$1" | sed 's/"/\&quot;/g'
}

helper() {
    cat <<EOF
$(basename $0) - a notebook application for writing articles and stuff.
USAGE: $(basename $0) [OPTION]

Options are:
    -h, --help: shows this help message
    -n, --new: creates a new article
    -s, --search: searches the notebook for text
    -v, --view: views an article

Authored by kzimmermann - https://notabug.org/kzimmermann

EOF
}

newentry() {
    local title
    printf "Enter a title for the new entry: "
    read title
    title=$(sanitize "$title")
    "$EDITOR" -c 'set linebreak' -c 'set wrap' .tempfile
    cat .tempfile | sed 's/"/\&quot;/g' > .tempfile2
    decrypt
    sqlite3 book.db <<EOF
INSERT INTO articles (title, content)
VALUES ("$title", "$(cat .tempfile2)");
EOF
    rm .tempfile .tempfile2
    encrypt
}

search() {
    local token
    printf "Enter a string to search the database: "
    read token
    decrypt
    echo "Found the following articles matching:"
    token=$(sanitize "$token")
    results=$(sqlite3 book.db <<EOF
SELECT id, title FROM articles
WHERE
    title LIKE "%$token%" OR
    content LIKE "%$token%"
;
EOF
)
    for item in "$results"
    do
        echo "$item" | sed 's/\&quot;/"/g'
    done
    encrypt
}

view() {
    local token
    local article
    printf "Enter an ID to view an article: "
    read token
    decrypt
    token=$(sanitize "$token")
    article=$(sqlite3 book.db <<EOF 
SELECT content FROM articles WHERE id="$token";
EOF
)
    if [[ -n "$article" ]]
    then
        # this ugly hack seems to be the only way to wrap words in less...
        echo "$article" | sed 's/\&quot;/"/g' | 
        fold -s --width="$(tput cols)" | less
    else
        echo "No article found with that ID."
    fi
    encrypt
}

encrypt() {
    if [[ -z "$RECIPIENT" ]]
    then
        echo "No recipient found to encrypt the database to."
        exit 1
    fi
    gpg --encrypt -r "$RECIPIENT" book.db 
    shred -u book.db
    rm .book_bak.db.gpg
}

decrypt() {
    # Are we running in encrypted mode?
    if [[ -f book.db.gpg ]]
    then
        gpg --decrypt book.db.gpg > book.db
        mv book.db.gpg .book_bak.db.gpg
    fi
}

if [[ -z "$1" ]]
then
    helper
    exit 1
fi

while [[ -n "$1" ]]
do
    case "$1" in
        "-h" | "--help" ) 
            helper
            exit 0
            ;;
        "-n" | "--new" )
            newentry
            exit 0
            ;;
        "-s" | "--search" ) 
            search
            exit 0
            ;;
        "-v" | "--view" ) 
            view
            exit 0
            ;;
        * )
            echo "Error: unknown option '$1'"
            helper
            exit 1
            ;;
    esac
done

